#include <assert.h>

#include "filestream.h"

void filestream_create (FileStream *fs, char *filename)
{
  Stream *s = STREAM_CAST (fs);
  stream_create (s);

  s->write = filestream_write;
  s->read = filestream_read;
  s->seek = filestream_seek;
  s->pos = filestream_pos;
  s->size = filestream_size;
  s->close = filestream_close;

  fs->file = fopen (filename, "w+b");
  assert (fs->file);
}

void filestream_write (Stream *s, void *src, int size)
{
  FileStream *fs = FILESTREAM_CAST (s);

  int nwrit = fwrite (src, 1, size, fs->file);

#ifdef WIN32
  fflush (fs->file);
#endif
}

int filestream_read (Stream *s, void *dest, int num_read, int dest_offset)
{
  FileStream *fs = FILESTREAM_CAST (s);

  int nread = fread ((char *)dest + dest_offset, num_read, 1, fs->file);

#ifdef WIN32
  fflush (fs->file);
#endif

  return nread;
}

void filestream_seek (Stream *s, int offset, SeekWhence whence)
{
  FileStream *fs = FILESTREAM_CAST (s);
  int w;
  int npos;
  int diff;

  switch (whence) {
    case SeekSet: w = SEEK_SET; npos = offset; break;
    case SeekCur: w = SEEK_CUR; npos = s->pos (s) + offset; break;
    case SeekEnd: w = SEEK_END; npos = s->size (s) + offset; break;
  }

  diff = npos - s->size (s);

  if (diff > 0) {
    char c = 0;
    int i;
    s->seek (s, 0, SeekEnd);
    for (i = 0; i < diff; ++i)
      s->write (s, &c, 1);

    return;
  }

  fseek (fs->file, offset, whence);
}

int filestream_pos (Stream *s)
{
  FileStream *fs = FILESTREAM_CAST (s);
  return ftell (fs->file);
}

int filestream_size (Stream *s)
{
  FileStream *fs = FILESTREAM_CAST (s);
  int pos;
  int size;
  pos = ftell (fs->file);
  fseek (fs->file, 0, SEEK_END);
  size = ftell (fs->file);
  fseek (fs->file, pos, SEEK_SET);
  return size;
}

void filestream_close (Stream *s)
{
  FileStream *fs = FILESTREAM_CAST (s);
  fclose (fs->file);
}
